<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>从化绿波-方案配置</title>
</head>
<link href="../../css/index.css" rel="stylesheet">
<style>
  .scheme-config {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
  }

  .scheme-btn {
    position: absolute;
  }

  input {
    height: 25px;
  }

  .scheme-content {
    display: flex;
    width: 100%;
    height: 100%;
  }

  .scheme-table {
    flex: 1;
    background-color: #fff;
    padding: 10px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    height: 100%;
    box-sizing: border-box;
  }

  .sub-list {
    flex: 0 0 150px;
    background-color: #fff;
    height: 100%;
    padding: 10px;
    box-sizing: border-box;
    margin-right: 8px;
  }

  .sub-item {
    /* padding: 10px 0; */
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-right: 10px;
    padding: 10px 5px;
  }

  .active-sub {
    background: linear-gradient(to right, rgba(64, 158, 255, 0.3), #fff);
  }

  .run-time {
    display: flex;
    align-items: center;
    margin-bottom: 10px;
  }

  .drawer-content {
    display: flex;
    flex-direction: column;
  }

  .scheme-item {
    border: 1px solid #ccc;
    padding: 10px 10px 0 10px;
    margin-bottom: 10px;
    border-radius: 8px;
  }

  .active-scheme {
    border: 2px solid rgba(72, 159, 252, 0.5);
  }

  .base-msg {
    display: flex;
    margin-bottom: 10px;
  }

  .base-msg-item {
    flex: 1;
    display: flex;
    align-items: center;
  }

  .base-msg-item .label {
    flex: 0 0 90px;
    text-align: right;
    margin-right: 10px;
  }

  .label-changed {
    text-decoration: underline;
    text-underline-offset: 5px;
    color: #489ffc;
  }

  .green-label {
    margin-right: 10px;
  }

  .base-msg-item select {
    width: 100%;
  }

  .base-msg-item input {
    height: 32px;
    width: 100%;
  }

  .base-msg-item-2 {
    flex: 2;
  }

  .base-stage-item {
    display: flex;
    margin-right: 20px;
    align-items: center;
  }

  .base-stage-item input {
    width: 50px;
    /* margin-left: 10px; */
  }

  .copy-content {
    display: flex;
  }
  .copy-scheme-item {
    padding: 3px 10px;
    margin-right: 10px;
    border-radius: 4px;
    border: 1px solid #489ffc;
  }

  .copy-scheme-item.active {
    background-color: #489ffc;
    color: #fff;
  }

  .percent {
    font-size: 12px;
    color: rgba(0,0,0,0.8);
    position: relative;
    top: 5px;
  }

</style>

<body>
  <div class="page-container" id="scheme-config">
    <div class="page-select">
      <div v-for="item in pageTab" @click="changeTab(item)" :key="item.key" class="select-item"
        :class="item.key === 'scheme-config' ? 'active-select': ''">
        {{item.label}}
      </div>
      <img class="login-out" src="../../assets/exit.png" alt="退出登录" title="退出登录" @click="handleLoginOut" />
    </div>
    <div class="iframe-container">
      <div class="scheme-config">
        <div class="message" :class="message.type" v-if="message.text">{{message.text}}</div>
        <template v-if="alert.text">
          <div class="dialog-cover alert-dialog-cover"></div>
          <div class="alert-dialog dialog">
            <div class="dialog-title alert-dialog-title">
              提示
            </div>
            <div class="dialog-content">
              {{alert.text}}
            </div>
            <div class="dialog-footer alert-dialog-footer">
              <template v-if="alert.type === MESSAGE_TYPE.ALERT">
                <button class="primary-btn" @click="cancelConfirm">确定</button>
              </template>
              <template v-if="alert.type === MESSAGE_TYPE.CONFIRM">
                <button class="cancel-btn" @click="cancelConfirm">取消</button>
                <button class="primary-btn" @click="handleConfirm(alert)">确定</button>
              </template>
            </div>
          </div>
        </template>
        <div class="scheme-content">
          <div class="sub-list">
            <div class="common-title">子区列表</div>
            <div v-for="item in baseData" @click="handleChangeSub(item)" class="sub-item"
              :class="item.subId === currentSub.subId ? 'active-sub' : ''">
              <div>
                {{item.subId}}
              </div>
            </div>
          </div>
          <div class="scheme-table">
            <div class="common-title">子区【{{currentSub.subId}}】路口方案</div>
            <div class="table-content">
              <table style="width: 100%" border="1">
                <tr>
                  <!-- <th class="cross-title">运行时段</th> -->
                  <th class="cross-title">方案号</th>
                  <th class="cross-title">路口</th>
                  <th class="cross-title">主相位</th>
                  <th class="cross-title green-split">绿信比</th>
                  <th class="cross-title">相位差</th>
                  <th class="cross-title">周期长</th>
                  <th class="cross-title width-150">编辑</th>
                </tr>
                <tr v-for="item in currentSiteList.list" class="center" :class="Number(item.plno) % 2 === 1 ? 'odd' : 'even'">
                  <!-- 方案号 -->
                  <td :rowspan="item.rowNum" v-if="item.isFirst">
                    {{item.plno}}
                    <!-- <img src="../../assets/bianji.png" alt="编辑" @click="handleEdit(item)"> -->
                  </td>
                  <!-- 路口 -->
                  <th>{{item.site}}</th>
                  <!-- 方案号 -->
                  <!-- <td>{{item.plno}}</td> -->
                  <!-- 主相位 -->
                  <td>{{item.varph}}</td>
                  <!-- 绿信比 -->
                  <td style="text-align: left;">{{item.split}}</td>
                  <!-- 相位差 -->
                  <td>{{item.offset}}</td>
                  <!-- 周期长 -->
                  <td>{{item.cycle}}</td>
                  <td :rowspan="item.rowNum" v-if="item.isFirst">
                    <button @click="handleEdit(item)">编辑</button>
                    <button :disabled="!item.varph" @click="handleCopy(item)">复制到</button>
                    <button :disabled="!item.varph" class="del-btn-text" @click="handleClear(item)">清除</button>
                  </td>
                </tr>
                <tr v-if="!currentSiteList.list.length" class="center">
                  <td colspan="7">暂无数据</td>
                </tr>
                <tr v-if="loading.table">
                  <th colspan="15">
                    <img src="../../assets/jiazai.png" class="loading" />
                  </th>
                </tr>
              </table>
            </div>
          </div>
        </div>
        <template v-if="editData.length">
          <div class="dialog-cover"></div>
          <div class="drawer">
            <div class="drawer-title">
              <div>
                子区：【{{currentSub.subId}}】 - 方案号：【{{editData[0].plno}}】方案编辑
              </div>
              <div @click="handleClose">
                <img src="../../assets/guanbi.png" />
              </div>
            </div>
            <div class="drawer-content drawer-content">
              <div v-for="(item, index) in editData">
                <div class="common-title">{{item.site}}</div>
                <div :class="['scheme-item', {'active-scheme': Number(item.site) === Number(currentSub.subId)}]">
                  <div class="base-msg">
                    <div class="base-msg-item">
                      <div :class="['label', {'label-changed': hasDiff(item, index, 'plno')}]">方案号:</div>
                      <select v-model="item.plno" :disabled="true" @change="handleChangeMultiData(item, 'plno')">
                        <option v-for="item in SCHEME_CONFIG" :key="item" :value="item">{{item}}</option>
                      </select>
                    </div>
                    <div class="base-msg-item">
                      <div :class="['label', {'label-changed': hasDiff(item, index, 'cycle')}]">周期长:</div>
                      <input min="0" step="1"
                         v-model="item.cycle" :disabled="Number(item.site) !== Number(currentSub.subId)" 
                         onkeydown="return event.keyCode !== 69 && event.keyCode !== 189" 
                         oninput="this.value = Math.abs(this.value)"
                         @input="handleChangeMultiData(item, 'cycle')" 
                         type="number" />
                    </div>
                    <div class="base-msg-item">
                      <div :class="['label', {'label-changed': hasDiff(item, index, 'offset')}]">相位差:</div>
                      <input v-model="item.offset" type="number"
                        :disabled="Number(item.site) === Number(currentSub.subId)" 
                        onkeydown="return event.keyCode !== 69 && event.keyCode !== 189" 
                        oninput="this.value = Math.abs(this.value)"/>
                    </div>
                  </div>
                  <div class="base-msg">
                    <div class="base-msg-item">
                      <div class="label">可选相位:</div>
                      <div>{{currentAreaStage(item.site).stage}}</div>
                    </div>
                    <div class="base-msg-item">
                      <div :class="['label', {'label-changed': hasDiff(item, index, 'phaseSort')}]">相位相序:</div>
                      <input v-model="item.phaseSort" @input="validateUppercase(item)" />
                    </div>
                    <div class="base-msg-item">
                      <div :class="['label', {'label-changed': hasDiff(item, index, 'varph')}]">主相位:</div>
                      <select v-model="item.varph">
                        <option v-for="item in currentAreaStage(item.site).stageList" :key="item" :value="item">{{item}}</option>
                      </select>
                    </div>
                  </div>
                  <div class="base-msg">
                    <div class="base-msg-item">
                      <div class="label">绿信比(s):</div>
                      <div v-for="(child, childIndex) in item.stageConfig" class="base-stage-item">
                        <div :class="['green-label', {'label-changed': child.value - 0 !== editBackData[index].stageConfig?.[childIndex]?.value - 0}]">
                          <template v-if="child.key !== item.varph">{{child.key}}:</template>
                          <template v-else>
                            <{{child.key}}>:
                          </template>
                        </div>
                        <input v-model="child.value" :disabled="disabledStage(item.site, child.key)" type="number"
                        onkeydown="return event.keyCode !== 69 && event.keyCode !== 189" 
                        oninput="this.value = Math.abs(this.value)"/>
                      </div>
                    </div>
                    
                  </div>
                  <div class="base-msg">
                    <div class="base-msg-item">
                      <div class="label" style="opacity: 0;">绿信比(%):</div>
                      <div v-for="(child, childIndex) in item.stageConfig" class="base-stage-item">
                        <div :class="['green-label', {'label-changed': child.value - 0 !== editBackData[index].stageConfig?.[childIndex]?.value - 0}]">
                          <template v-if="child.key !== item.varph">{{child.key}}:</template>
                          <template v-else>
                            <{{child.key}}>:
                          </template>
                        </div>
                        <!-- <input v-model="child.value" :disabled="disabledStage(item.site, child.key)" type="number" /> -->
                        <div  style="width: 50px;">
                          <span v-if="child.key !== item.varph">
                            {{item.cycle ? Math.round(child.value / item.cycle * 100) : 0}}%
                          </span>
                          <span v-else>
                            {{getPercent(item)}}%
                          </span>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
            <div class="drawer-footer">
              <button class="cancel-btn" @click="handleClose">取消</button>
              <button class="primary-btn" @click="handleSure">确定</button>
            </div>
          </div>
        </template>
        <template v-if="resultEditData.length">
          <div class="dialog-cover"></div>
          <div class="dialog">
            <div class="dialog-title">
              <div>
                子区【{{currentSub.subId}}】- 方案号【{{resultEditData[0].plno}}】编辑信息确认
              </div>
              <img src="../../assets/guanbi.png" alt="" class="pointer" @click="handleCloseDialog">
            </div>
            <div class="dialog-content">
              <table>
                <tr>
                  <th class="cross-title">路口</th>
                  <!-- <th class="cross-title">方案号</th> -->
                  <th class="cross-title">主相位</th>
                  <th class="cross-title green-split">绿信比</th>
                  <th class="cross-title">相位差</th>
                  <th class="cross-title">周期长</th>
                </tr>
                <tr v-for="item in resultEditData" class="center">
                  <!-- 路口 -->
                  <th>{{item.site}}</th>
                  <!-- 方案号 -->
                  <!-- <td>{{item.plno}}</td> -->
                  <!-- 主相位 -->
                  <td>{{item.varph}}</td>
                  <!-- 绿信比 -->
                  <td style="text-align: left;">{{item.split}}</td>
                  <!-- 相位差 -->
                  <td>{{item.offset}}</td>
                  <!-- 周期长 -->
                  <td>{{item.cycle}}</td>
                </tr>
              </table>
            </div>
            <div class="dialog-footer">
              <button class="cancel-btn" @click="handleCloseDialog">取消</button>
              <button class="primary-btn" @click="handleSureSave">
                <img src="../../assets/jiazai.png" class="loading" v-if="loading.save" />确认
              </button>
            </div>
          </div>
        </template>
        <template v-if="copyData.plno">
          <div class="dialog-cover"></div>
          <div class="dialog">
            <div class="dialog-title">将子区【{{currentSub.subId}}】方案【{{copyData.plno}}】复制到</div>
            <div class="dialog-content">
              <div class="copy-content">
                <div 
                  :class="['copy-scheme-item pointer', {'active': copyedPlno === item}]"
                  @click="copyedPlno = item"
                  v-for="item in SCHEME_CONFIG.filter(item => item != copyData.plno)">
                  {{item}}
                </div>
              </div>
            </div>
            <div class="dialog-footer">
              <button class="cancel-btn" @click="handelCancelCopy">取消</button>
              <button class="primary-btn" :disabled="!copyedPlno" @click="handleSureCopy">确认</button>
            </div>
          </div>
        </template>
      </div>
    </div>
  </div>
  
</body>
<script src="../../js/vue3.js"></script>
<script src="../../config.js"></script>
<script src="../../js/api/secondEdition.js"></script>
<script src="../../js/dict/schemeConfig.js"></script>
<script src="../../js/method.js"></script>
<script>
  const { createApp, ref, nextTick, reactive, onMounted, onUnmounted, watch, computed } = Vue
  const app = createApp({
    setup() {
      /** 消息弹窗相关代码 ------------ start ------------ */
      const MESSAGE_TYPE = {
        'SUCCESS': 'success',
        'INFO': 'info',
        'ALERT': 'alert',
        'ERROR': 'error',
        'CONFIRM': 'confirm'
      }

      const loading = reactive({
        table: false, // 表格刷新
        save: false, // 保存编辑的数据
      })

      const message = reactive({
        type: '',
        text: ''
      })

      const alert = reactive({
        type: '',
        text: '',
        item: '',
        methods: null
      })

      // 弹窗消息1.5秒消失
      watch(
        () => message.text,
        () => {
          if (message.text) {
            setTimeout(() => {
              message.text = ''
            }, 3000)
          }
        }
      )
      /** 消息弹窗相关代码 ------------ end ------------ */

      /** 业务相关代码 ------------ start ------------ */

      // 转换前的数据
      let baseData = ref([])

      let currentSub = ref({})

      // watch(
      //   () => currentSub.value.subId,
      //   () => {
      //     currentSub.value.subId && getAreaScheme(currentSub.value.subId)
      //   },
      //   {
      //     immediate: true
      //   }
      // )

      // 处理模拟数据
      const apiPreFix = computed(() => {
        return isMock ? '' : apiUrl
      })

      // 处理模拟数据
      const api = computed(() => {
        return isMock ? mockApi : realApi
      })

      // 初始化方案信息
      const initScheme = computed(() => {
        let schemeConfig = {}        
        SCHEME_CONFIG?.forEach(plno => {
          schemeConfig[plno] = []
        })        
        currentSub.value.siteList?.forEach(item => {
          for(let i in schemeConfig) {
            schemeConfig[i].push({
              site: item.siteId,
              plno: i
            })
          }
        })        
        return schemeConfig
      })

      // 当前子区的数据
      const currentSiteList = computed(() => {
        // 获取到当前子区的路口
        const siteList = currentSub.value.siteList?.map(item => Number(item.siteId))        
        let data = []
        // 初始化时间数据
        let schemeSort = JSON.parse(JSON.stringify(initScheme.value))     
        // 扁平化获取到的数据  
        // let flatArr = []
        // allData.value.forEach(item => {
        //   flatArr = flatArr.concat(item)
        // })
        // 将数据分类
        allData.value.forEach((item, itemIndex) => {
          if (!schemeSort[item.plno]) {
            schemeSort[item.plno] = []
          }
          schemeSort[item.plno].forEach((ele, eleIndex) => {
            if (ele.site == item.site) {
              schemeSort[item.plno][eleIndex] = item
            }
          })
        })
        
        // 处理数据的合并行数
        for (let i in schemeSort) {
          schemeSort[i].forEach((item, itemIndex) => {
            item.isFirst = itemIndex === 0
            item.rowNum = schemeSort[i]?.length || 1
          })
        }
        let sortFlatArr = []
        for (let i in schemeSort) {
          sortFlatArr = sortFlatArr.concat(schemeSort[i])
        }
        return {
          list: sortFlatArr,
          schemeList: schemeSort
        }
      })

      // 获取接口返回的数据
      const getInitData = () => {
        handleChangeSub(baseData.value[0])
      }

      // 子区切换
      const handleChangeSub = (item) => {
        currentSub.value = item
      }

      // 接口返回的全部子区信息
      const allData = ref([])

      // 获取子区的方案信息
      // const getAreaScheme = (site) => {
      //   allData.value = []
      //   SCHEME_CONFIG.forEach(plno => {
      //     getCrossScheme(site, plno)
      //   })
      // }

      // 获取子区的方案信息
      const getCrossScheme = () => {
        // fetch(`${apiPreFix.value}${api.value.getPlans}?site=${site}&plno=${plno}`)
        fetch(`${apiPreFix.value}${api.value.getPlans}`)
        .then(res => res.json())
        .then(res => {
          allData.value = res
        })
      }

      const timeConfig = ref([])
      // 获取时段配置
      const getTimeConfig = (flag = false) => {
        fetch(apiPreFix.value + api.value.getEnableTime)
          .then(res => res.json())
          .then(res => {
            timeConfig.value = res
          })
      }

      // 方案是否被使用到
      const plnoHasUsed = (plno) => {
        const currentTimeList = timeConfig.value.filter(item => item.master === currentSub.value.subId)
        const resultPlno = currentTimeList.find(item => item.plno == plno)
        return resultPlno
      }
      /** 业务相关代码 ------------ end ------------ */

      /** 弹窗相关代码---------------  start  ---------------*/

      // 绿信比配置
      const stageConfig = []
      // 初始化绿信比数据
      STAGE_CONFIG.forEach(item => {
        stageConfig.push({
          key: item, value: 0
        })
      })
      // 用于标注修改的原始数据
      const editBackData = ref([])
      const editData = ref([])
      /**
       * 编辑子区的时段配置
       */
      const handleEdit = (data) => {
        editData.value = JSON.parse(JSON.stringify(currentSiteList.value.schemeList[data.plno]))
        editData.value.forEach(item => {
          // 初始化相位相序
          item.phaseSort = []
          const tempData = item.split?.split(', ')
          // 初始化stageCode
          item.stageConfig = JSON.parse(JSON.stringify(stageConfig))
          tempData?.forEach(ele => {
            const splitData = ele?.split(':')
            // 初相位相序赋值
            item.phaseSort.push(splitData[0])
            // 给stageCode赋值
            item.stageConfig.forEach(stageItem => {
              if (stageItem.key === splitData[0]) {
                stageItem.value = splitData[1]
              }
            })
          })
          // 相位相序处理为字符串
          item.phaseSort = item.phaseSort.join('')
        })
        editBackData.value = JSON.parse(JSON.stringify(editData.value))
      }

      // 关闭时候校验，有未保存数据提示
      const handleClose = (flag = true) => {
        const changeFlag = hasChange()
        if (changeFlag) {
          alert.text = `当前有未保存的数据，关闭后数据会丢失，确认关闭吗?`
          alert.type = MESSAGE_TYPE.CONFIRM
          alert.methods = 'cancelSave'
          return
        }
        editData.value = []
      }
      

      // 关闭弹窗
      const handleCloseDialog = () => {
        resultEditData.value = []
      }

      // 确定保存
      const handleSureSave = () => {
        alert.text = `确定修改子区【${currentSub.value.subId}】- 方案【${resultEditData.value[0].plno}】的数据吗?`
        alert.type = MESSAGE_TYPE.CONFIRM
        alert.methods = 'savePlan'
        alert.item = {
          plno: resultEditData.value[0].plno,
          data: resultEditData.value
        }
      }

      // 方案保存
      const savePlan = ({plno, data}) => {
        // const plno = resultEditData.value[0].plno
        // const data = resultEditData.value
        loading.save = true
          fetch(apiPreFix.value + api.value.setPlans, {
            method: 'POST',
            body: JSON.stringify({
              master: currentSub.value.subId,
              plno,
              data
            }),
            headers: {
              'content-type': 'application/json'
            }
          })
            .then(res => res.json())
            .then(res => {
              if (!res.err) {
                message.text = `操作成功`
                message.type = MESSAGE_TYPE.SUCCESS
                getCrossScheme()
                handleCloseDialog()
                editData.value = []
                copyData.value = {}
              }
              else {
                message.text = res.err || `操作失败`
                message.type = MESSAGE_TYPE.ERROR
              }
              if(res.code === 401) {
                goLogin()
              }
            })
            .catch((res) => {
              message.text = res.err || `操作失败`
              message.type = MESSAGE_TYPE.ERROR
            })
            .finally(() => {
              loading.save = false
            })
      }

      const cancelSave = () => {
        // 取消保存
        editData.value = []
        cancelConfirm()
      }

      // 取消操作
      const cancelConfirm = () => {
        alert.type = ''
        alert.text = ''
        alert.methods = ''
        alert.item = ''
      }

      // 确认操作
      const handleConfirm = async (alert) => {
        try {
          await methodsList[alert.methods](alert.item)
          cancelConfirm()
        } catch {
          cancelConfirm()
        }
      }

      // 方案清除
      const handleClear = (item) => {
        const hasUsed = plnoHasUsed(item.plno)
        if (hasUsed) {
          // alert(`方案在时段【${hasUsed.time}】中被使用，不可清除`)
          alert.text = `方案在时段【${hasUsed.time}】中被使用，不可清除`
          alert.type = MESSAGE_TYPE.ALERT
          return
        }
        // const result = confirm(`清除后不可恢复，确认清除方案【${item.plno}】吗?`)
        alert.text = `清除后不可恢复，确认清除方案【${item.plno}】吗?`
        alert.type = MESSAGE_TYPE.CONFIRM
        alert.methods = 'savePlan'
        alert.item = {
          plno: item.plno,
          data: []
        }
        // result && savePlan(item.plno, [])
      }

      // 被复制的方案信息
      const copyData = ref({})
      // 复制到的方案号
      const copyedPlno = ref('')
      const handleCopy = (item) => {
        copyData.value = item
        copyedPlno.value = ''
      }

      // 取消复制
      const handelCancelCopy = () => {
        copyData.value = {}
      }

      // 确定复制
      const handleSureCopy = () => {
        // const result = confirm(`确定将子区【${currentSub.value.subId}】方案【${copyData.value.plno}】的内容复制到方案【${copyedPlno.value}】吗?`)
        alert.type = MESSAGE_TYPE.CONFIRM
        alert.text = `确定将子区【${currentSub.value.subId}】方案【${copyData.value.plno}】的内容复制到方案【${copyedPlno.value}】吗?`
        alert.methods = 'confirmCopy'        
      }

      // 确定复制
      const confirmCopy = () => {
        const currentArea = SUB_LIST.value.find(item => item.master === currentSub.value.subId)
        const list = allData.value.filter(item => item.plno === copyData.value.plno && currentArea.slave.includes(item.site))
        const copyList = JSON.parse(JSON.stringify(list))
        const resultList = []
        copyList.forEach(item => {
          resultList.push({
            site: item.site,
            time: item.time,
            cycle: item.cycle,
            plno: copyedPlno.value,
            varph: item.varph,
            split: item.split,
            offset: item.offset,
          })
        })
        savePlan({plno: copyedPlno.value, data: resultList})
      }
      /**
       * 修改联合状态
       */
      const handleChangeMultiData = (data, type) => {
        editData.value.forEach(item => {
          item[type] = data[type]
        })
      }

      // 相位相序校验
      const validateUppercase = (item) => {          
        const {stage, stageList} = currentAreaStage.value(item.site) 
        const reg = new RegExp(`[^${stage}]`, 'gi')          
        // 转换为大写并移除非A-Z字符
        let value = item.phaseSort.toUpperCase().replace(reg, '');
        
        // 去重处理 - 只保留每个字母的第一次出现
        let uniqueChars = [];
        for (let char of value) {
            if (!uniqueChars.includes(char)) {
                uniqueChars.push(char);
            }
        }
        // 更新输入框的值（最多7个字母）
        item.phaseSort = uniqueChars.join('').slice(0, stageList.length);
      }

      // 是否有差异
      const hasDiff = computed(() => {
        return (item, index, key) => {
          return item[key] != editBackData.value[index]?.[key]
        }
      })

      const diffKey = ['plno', 'cycle', 'offset', 'phaseSort', 'varph']

      // 保存时候判断数据是否有修改
      const hasChange = () => {
        let flag = false
        editData.value.forEach((item, index) => {
          // 基础数据判断
          diffKey.forEach(key => {
            if (hasDiff.value(item, index, key)) {
              flag = true
            }
          })
          // 绿信比判断
          item.stageConfig.forEach((child, childIndex) => {
            if (child.value  != editBackData.value[index].stageConfig?.[childIndex]?.value) {
              flag = true
            }
          })
        })
        return flag
      }

      // 保存时候是否有数据未填写
      const hasNoEnter = () => {
        let flag = false
        editData.value.forEach((item, index) => {
          diffKey.forEach(key => {
            if(!item[key] && (key !== 'offset' && item[key] == 0 )) {
              flag = true
            }
          })
        })
        return flag
      }

      /**
       * 计算周期与各阶段是否匹配
       * 各阶段时长相加需要与周期相等
       */
      const cycleIsError = () => {
        let cycleErrorFlag = false
        let cycleErrorData = {}
        const reverseData = JSON.parse(JSON.stringify(editData.value)).reverse()
        reverseData.forEach((item) => {
          const stageArr = item.stageConfig.map(item => item.value - 0)
          const countCycle = stageArr.reduce((acc, curr) => acc + curr, 0)
          if (countCycle !== Number(item.cycle)) {
            cycleErrorFlag = true
            cycleErrorData = item
          }
        })
        return {
          cycleErrorFlag,
          cycleErrorData
        }
      }

      /**
       * 校验绿信比数据是否正确
       * 1、相位相序的每个阶段必须有时长
       * 2、有时长配置的阶段必须出现在相位相序里面
       */
      const splitDataIsError = () => {
        let splitErrorFlag = false
        let splitErrorData = {}
        editData.value.forEach((item) => {
          let tempSplit = ''
          const sortArr = item.phaseSort?.split('')
          // 如果相位相序中存在的在绿信比中值为空或者0，则判断错误
          sortArr.forEach((sortItem, sortIndex) => {
            const result = item.stageConfig.find(stageItem => stageItem.key === sortItem)            
            if (!result.value || result.value == '0') {
              splitErrorFlag = true
              splitErrorData = {...item, result}
            }
          })
          // 如果绿信比中配置了值，但是相位相序中不存在，则判断错误
          item.stageConfig.forEach(result => {
            if (Number(result.value)) {
              if(!sortArr.includes(result.key)) {
                splitErrorFlag = true
                splitErrorData = {...item, result}
              }
            }
          })
        })
        return { splitErrorFlag, splitErrorData }
      }

      // 编辑的数据转换
      const editDataTransform = () => {
        let saveData = []
        editData.value.forEach((item) => {
          let tempSplit = ''
          const sortArr = item.phaseSort?.split('')
          sortArr.forEach((sortItem, sortIndex) => {
            const result = item.stageConfig.find(stageItem => stageItem.key === sortItem)
            tempSplit += `${result.key}:${result.value}${sortIndex === sortArr.length - 1 ? '' : ', '}`
          })
          item.split = tempSplit
          saveData.push({
            site: item.site,
            time: item.time,
            cycle: item.cycle,
            plno: item.plno,
            varph: item.varph,
            split: item.split,
            offset: item.offset,
          })     
        })
        return saveData
      }

      let resultEditData = ref([])
      // 确定编辑
      const handleSure = () => {
        // 检查是否有数据未填写
        const enterFlag = hasNoEnter()
        if (enterFlag) {
          message.type = MESSAGE_TYPE.ALERT
          message.text = '请完整填写各路口的方案信息'
          return
        }
        // 检查是否有修改
        const changeFlag = hasChange()
        if (!changeFlag) {
          message.type = MESSAGE_TYPE.ALERT
          message.text = '数据未修改，无需进行保存'
          return
        }
        // 检查周期时长
        const {cycleErrorFlag, cycleErrorData} = cycleIsError()
        if (cycleErrorFlag) {
          // message.type = MESSAGE_TYPE.ERROR
          // message.text = `路口【${cycleErrorData.site}】周期长需要等于各阶段时长的总和，请检查`
          // alert(`路口【${cycleErrorData.site}】周期长需要等于各阶段时长的总和，请检查`)
          alert.type = MESSAGE_TYPE.ALERT
          alert.text = `路口【${cycleErrorData.site}】周期长需要等于各阶段时长的总和，请检查`
          return
        }
        // 检查相位相序和绿信比
        const {splitErrorFlag, splitErrorData} = splitDataIsError()
        if (splitErrorFlag) {
          // message.type = MESSAGE_TYPE.ERROR
          // message.text = `路口【${splitErrorData.site}】中阶段【${splitErrorData.result.key}】与相位相序不匹配，请检查`
          // alert(`路口【${splitErrorData.site}】中阶段【${splitErrorData.result.key}】与相位相序不匹配，请检查`)
          alert.type = MESSAGE_TYPE.ALERT
          alert.text = `路口【${splitErrorData.site}】中阶段【${splitErrorData.result.key}】与相位相序不匹配，请检查`
          return
        }
        resultEditData.value = editDataTransform()
      }

      /** 弹窗相关代码 ------------ end ------------ */

      // 获取可变阶段的百分比
      const getPercent = computed(() => {
        return (item) => {
          const otherStage = item.stageConfig.filter(ele => ele.key !== item.varph)
          let percent = 100
          item.cycle && otherStage.forEach(child => {
            percent -= Math.round(child.value / item.cycle * 100)
          })
          return item.cycle ? percent : 0
        }
      })
      // 当前阶段的可选阶段
      const currentAreaStage = computed(() => {
        return (ssId) => {
          const stage = CAN_USE_STAGE.value.find(item => item.id === ssId).avialiable          
          const stageList = stage?.split('') ?? []
          return {stage, stageList}
        }
      })

      const disabledStage = computed(() => {
        return (ssId, stage) => {
          const {stageList} = currentAreaStage.value(ssId)
          return !stageList.includes(stage)
        }
      })

      const handleLoginOut = () => {
        alert.text = `确定退出登录吗?`
        alert.type = MESSAGE_TYPE.CONFIRM
        alert.methods = 'goLogin'
      }

      const methodsList = {
        'cancelSave': cancelSave,
        'savePlan': savePlan,
        'confirmCopy': confirmCopy,
        'goLogin': goLogin
      }

      const TIME_LIST = ref([])
      const CAN_USE_STAGE = ref([])
      const SUB_LIST = ref([])
      onMounted(() => {
        hasLogin(apiPreFix.value)
        const sessionData = JSON.parse(window.sessionStorage.getItem('BASE_DICTS'))
        // 处理无缓存时候的情况，跳转去首页进行重新处理缓存，并记录当前页面信息
        if (!sessionData) {
          window.location.replace(window.location.origin)
          const currentPage = pageTab.find(item => item.key === 'scheme-config')
          currentPage && window.sessionStorage.setItem('CURRENT_PAGE', JSON.stringify(currentPage))
        }
        baseData.value = sessionData.subMsg
        SUB_LIST.value = sessionData.areas
        TIME_LIST.value = sessionData.times
        CAN_USE_STAGE.value = sessionData.sites
        getInitData()
        getCrossScheme()
        getTimeConfig()
      })

      return {
        message,
        loading,
        baseData,
        currentSub,
        allData,
        currentSiteList,
        editData,
        stageConfig,
        SCHEME_CONFIG,
        STAGE_CONFIG,
        editBackData,
        hasDiff,
        resultEditData,
        CAN_USE_STAGE,
        currentAreaStage,
        disabledStage,
        pageTab,
        changeTab,
        copyData,
        copyedPlno,
        getPercent,
        alert,
        MESSAGE_TYPE,
        handleSureCopy,
        handelCancelCopy,
        handleCopy,
        handleClear,
        handleChangeSub,
        handleEdit,
        handleClose,
        handleChangeMultiData,
        validateUppercase,
        handleSure,
        handleCloseDialog,
        handleSureSave,
        handleConfirm,
        cancelConfirm,
        handleLoginOut
      }
    }
  })
  app.mount("#scheme-config");
</script>

</html>